﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace VisualCode.Client
{
    public class VisualCompiler : IDisposable
    {

        public VisualCompiler(VisualProject project)
        {
            if (project == null)
                throw new ArgumentNullException("project");

            this.Project = project;
        }

        public bool Compile()
        {
            //Create an assembly name
            AssemblyName assemblyName = new AssemblyName(this.Project.Name);

            //Assembly builder
            AssemblyBuilder assemblyBuilder
                = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);

            //Module builder
            ModuleBuilder moduleBuilder
                = assemblyBuilder.DefineDynamicModule(this.Project.Name, this.Project.Name + ".dll", true);

            foreach (VisualNamespace visualNamespace in this.Project.Namespaces)
            {
                //Create the types
                foreach (VisualClass visualClass in visualNamespace.Types.OfType<VisualClass>())
                {
                    string typename = visualClass.Name;

                    if (!string.IsNullOrEmpty(visualNamespace.Name))
                        typename = visualNamespace.Name + "." + visualClass.Name;

                    TypeBuilder typeBuilder
                        = moduleBuilder.DefineType(typename, TypeAttributes.Public | TypeAttributes.Class);

                    if (visualClass.Fields != null)
                    {
                        foreach (VisualField visualField in visualClass.Fields)
                        {
                            if (visualField.Type.ReferenceType == TypeReferenceType.NETType)
                            {
                                //TODO - properly scope the field
                                FieldBuilder fieldBuilder = typeBuilder.DefineField(visualField.Name, visualField.Type.NetType, FieldAttributes.Public);
                            }
                        }
                    }

                    if (visualClass.Properties != null)
                    {
                        foreach (VisualProperty visualProperty in visualClass.Properties)
                        {
                            //
                        }
                    }

                    typeBuilder.CreateType();
                }
            }

            //Create the global functions
            moduleBuilder.CreateGlobalFunctions();

            //Save this thing
            assemblyBuilder.Save(this.Project.Name + ".dll");


            return true;
        }

        /// <summary>
        /// Gets the project the is used to compile.
        /// </summary>
        public VisualProject Project { get; private set; }

        #region IDisposable Members

        public void Dispose()
        {
        }

        #endregion
    }
}
